﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SmartMeterParamFrame.Connection;

namespace CL2036
{
    public class CLDeviceControl : SmartMeterParamFrame.IDevice
    {

        private const string CONST_2036 = "19200,N,8,1";

        private SmartMeterParamFrame.IApplication application = null;

        private UI.UI_Config ConfigUI;

        private Model.SystemConfig m_Config = new CL2036.Model.SystemConfig();

        private UDPClient Client = new UDPClient();

        private UDPClient[] Clients;

        public CLDeviceControl()
        {
            m_Config.Load();
            Clients = new UDPClient[m_Config.ChannelCount];
        }

        #region IDevice 成员
        /// <summary>
        /// 总线数
        /// </summary>
        int SmartMeterParamFrame.IDevice.BusCount
        {
            get { return m_Config.ChannelCount; }
        }
        /// <summary>
        /// 表位数
        /// </summary>
        int SmartMeterParamFrame.IDevice.Bws
        {
            get { return m_Config.MeterBwCount; }
        }

        bool SmartMeterParamFrame.IDevice.DeviceLink(out string ErrString)
        {
            byte[] bytData = Protocol.CL2036Protocol.WeaveLink();

            ErrString = "";

            if (!senddata(ref bytData, true))
            {
                ErrString = "装置无响应...";
                return false;
            }

            if (!Protocol.CL2036Protocol.ExplainLink(bytData))
            {
                ErrString = "装置返回指令错误...";
                return false;
            }

            return true;
        }

        bool SmartMeterParamFrame.IDevice.DeviceOffLink(out string ErrString)
        {
            byte[] bytData = Protocol.CL2036Protocol.WeaveOffLine();
            ErrString = "";
            if (!senddata(ref bytData, true))
            {
                ErrString = "设备无响应...";
                return false;
            }

            if (!Protocol.CL2036Protocol.ExplainOffLine(bytData))
            {
                ErrString = "返回指令错误...";
                return false;
            }

            return true;
        }
        /// <summary>
        /// 是不是188H
        /// </summary>
        bool SmartMeterParamFrame.IDevice.IsChannnelConst
        {
            get { return m_Config.Is188H; }
        }
        /// <summary>
        /// 关源
        /// </summary>
        /// <param name="ErrString"></param>
        /// <returns></returns>
        bool SmartMeterParamFrame.IDevice.PowerOff(out string ErrString)
        {
            byte[] bytData = Protocol.CL2036Protocol.WeavePowerOff();
            ErrString = "";
            if (!senddata(ref bytData, true))
            {
                ErrString = "装置无响应...";
                return false;
            }

            if (!Protocol.CL2036Protocol.ExplainPowerOff(bytData))
            {
                ErrString = "装置返回指令错误...";
                return false;
            }

            return true;
        }

        bool SmartMeterParamFrame.IDevice.PowerOn(float U, out string ErrString)
        {
            List<byte[]> bytDatas = Protocol.CL2036Protocol.WeavePowerOn(m_Config.IsDx ? 7 : 0, U);
            ErrString = "";

            for (int i = 0; i < bytDatas.Count; i++)
            {
                byte[] bytData = bytDatas[i];

                if (!senddata(ref bytData, true))
                {
                    ErrString = "设备无响应...";
                    return false;
                }

                if (!Protocol.CL2036Protocol.ExplainPowerOn(bytData))
                {
                    ErrString = "返回指令错误...";
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 发送数据，电能表通信（485）
        /// </summary>
        /// <param name="bytData"></param>
        /// <param name="IsReturn"></param>
        /// <param name="Bwh"></param>
        /// <returns></returns>
        bool SmartMeterParamFrame.IDevice.SendData(ref byte[] bytData, bool IsReturn, int Bwh)
        {
            int channelNo = BwhToChannelNo(Bwh);
            Console.WriteLine("通道号:" + channelNo.ToString());
            if (Clients[channelNo] == null) Clients[channelNo] = new UDPClient();

            if (!Clients[channelNo].IsInit)
            {
                int OneChannelBws = m_Config.MeterBwCount / m_Config.ChannelCount;

                int RouteNo = (int)Bwh / OneChannelBws + (Bwh % OneChannelBws == 0 ? 0 : 1);        //获取线路号

                int intPort = ChannelToPort(m_Config.RouteChannel(RouteNo));
                Console.WriteLine("端口号:" + intPort.ToString() + "  " + RouteNo.ToString());

                Clients[channelNo].Init("2400,e,8,1", m_Config.CL20181IP, intPort, intPort + 1, 10003);

                if (!Clients[channelNo].IsInit) return false;
            }

            return Clients[channelNo].SendData(ref bytData, IsReturn);
        }

        void SmartMeterParamFrame.IDevice.SetWcb(byte WcbType, bool IsOpen)
        {
            byte[] bytData = Protocol.CL188.WcbSetup(WcbType, IsOpen);

            senddata(ref bytData, false);
        }

        void SmartMeterParamFrame.IDevice.SetWcb(int Bwh, bool IsOpen)
        {
            byte[] bytData = Protocol.CL188.WcbSetup(Bwh, IsOpen);

            senddata(ref bytData, false);
        }

        void SmartMeterParamFrame.IDevice.ShowUI()
        {
            if (application == null) return;

            ConfigUI = new UI.UI_Config(m_Config);

            ((System.Windows.Controls.TabItem)application.ControlPanel).Content = ConfigUI;

            application.Save += new EventHandler(application_Save);
        }

        int SmartMeterParamFrame.IDevice.ThreadCount
        {
            get { return m_Config.ThreadCount; }
        }

        SmartMeterParamFrame.IApplication SmartMeterParamFrame.IDevice.UISet
        {
            set { application = value; }
        }

        #endregion

        private void application_Save(object sender, EventArgs e)
        {
            foreach (UDPClient udpClient in this.Clients)
            {
                if (udpClient != null)
                    udpClient.Close();
            }
            Clients = new UDPClient[m_Config.ChannelCount];
            if (this.Client != null)
                this.Client.Close();
            this.Client = new UDPClient();
            application.IsSaveOK = ConfigUI.Save();
        }


        /// <summary>
        /// 自动重复3次(仅供2036使用)
        /// </summary>
        /// <param name="bytsend"></param>
        /// <param name="IsReturn"></param>
        /// <returns></returns>
        private bool senddata(ref byte[] bytsend, bool IsReturn)
        {
            if (!Client.IsInit)
            {
                int int2036Port = ChannelToPort(m_Config.CL2036Channel);

                Client.Init(CONST_2036, m_Config.CL20181IP, int2036Port, int2036Port + 1, 10003, 1000);

                if (!Client.IsInit) return false;
            }

            for (int i = 0; i < 3; i++)
            {
                byte[] BytData = new byte[bytsend.Length];

                Array.Copy(bytsend, BytData, bytsend.Length);

                if (Client.SendData(ref BytData, IsReturn))
                {
                    bytsend = BytData;
                    return true;
                }

                System.Threading.Thread.Sleep(200);     //停200MS再继续重试

            }
            return false;
        }
        /// <summary>
        /// 表位号转通道号
        /// </summary>
        /// <param name="Bwh"></param>
        /// <returns></returns>
        private int BwhToChannelNo(int Bwh)
        {
            return ((Bwh - 1) / (m_Config.MeterBwCount / m_Config.ChannelCount));
        }

        /// <summary>
        /// 通道转化为端口
        /// </summary>
        /// <param name="ChannelNo"></param>
        /// <returns></returns>
        private int ChannelToPort(int ChannelNo)
        {
            const int CONST_DEFPORT = 20000;
            return CONST_DEFPORT + (ChannelNo - 1) * 2;
        }
    }
}
